/*
 * Copyright (C) 2005 Luca Veltri - University of Parma - Italy
 * 
 * This file is part of MjSip (http://www.mjsip.org)
 * 
 * MjSip is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * MjSip is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with MjSip; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * 
 * Author(s):
 * Luca Veltri (luca.veltri@unipr.it)
 */

package org.zoolu.sip.provider;


import org.zoolu.tools.Configure;
import org.zoolu.tools.Parser;
import org.zoolu.tools.Log;
import org.zoolu.tools.RotatingLog;
import org.zoolu.tools.Timer;

import java.io.*;
import java.util.Vector;


/** SipStack includes all static attributes used by the sip stack.
  * <p>
  * Static attributes includes the logging configuration,
  * default SIP port, deafult supported transport protocols, timeouts, etc.
  */
public class SipStack extends Configure
{
   // ********************** private attributes **********************

   /** Whether SipStack configuration has been already loaded */
   private static boolean is_init=false;

   /** The default SipProvider */
   //private static SipProvider provider=null;


   // *********************** software release ***********************

   /** Release */
   public static final String release="mjsip stack 1.6";
   /** Authors */
   public static final String authors="Luca Veltri - University of Parma (Italy)";


   // ********************** static attributes ***********************

   /** String value "no-ua-info" used for setting no 'User-Agent' header filed. */
   //public static final String NO_UA_INFO="NO-UA-INFO";

   /** String value "no-server-info" used for setting no 'Server' header filed. */
   //public static final String NO_SERVER_INFO="NO-SERVER-INFO";
   

   // ************* default sip provider configurations **************

   /** Default SIP port.
    * Note that this is not the port used by the running stack, but simply the standard default SIP port.
    * <br> Normally it sould be set to 5060 as defined by RFC 3261. Using a different value may cause
    * some problems when interacting with other unaware SIP UAs. */
   public static int default_port=5060; 
   /** Default supported transport protocols. */
   public static String[] default_transport_protocols={ SipProvider.PROTO_UDP, SipProvider.PROTO_TCP };
   /** Default max number of contemporary open transport connections. */
   public static int default_nmax_connections=32;
   /** Whether adding 'rport' parameter on via header fields of outgoing requests. */
   public static boolean use_rport=true;
   /** Whether adding (forcing) 'rport' parameter on via header fields of incoming requests. */
   public static boolean force_rport=false;


   // ******************** general configurations ********************

   /** default max-forwards value (RFC3261 recommends value 70) */
   public static int max_forwards=70;
   /** starting retransmission timeout (milliseconds); called T1 in RFC2361; they suggest T1=500ms */
   public static long retransmission_timeout=500;  
   /** maximum retransmission timeout (milliseconds); called T2 in RFC2361; they suggest T2=4sec */
   public static long max_retransmission_timeout=4000;   
   /** transaction timeout (milliseconds); RFC2361 suggests 64*T1=32000ms */
   public static long transaction_timeout=32000;    
   /** clearing timeout (milliseconds); T4 in RFC2361; they suggest T4=5sec */
   public static long clearing_timeout=5000;
       
   /** Whether using only one thread for all timer instances. */
   public static boolean single_timer=false;

   /** Whether 1xx responses create an "early dialog" for methods that create dialog. */
   public static boolean early_dialog=false;

   /** Default 'expires' value in seconds. RFC2361 suggests 3600s as default value. */
   public static int default_expires=3600;

   /** UA info included in request messages in the 'User-Agent' header field.
     * Use "NONE" if the 'User-Agent' header filed must not be added. */
   public static String ua_info=release;
   /** Server info included in response messages in the 'Server' header field
     * Use "NONE" if the 'Server' header filed must not be added. */
   public static String server_info=release;
   

   // ************************ debug and logs ************************

   /** Base level (offset) for logging Transport events */
   public static int LOG_LEVEL_TRANSPORT=1;
   /** Base level (offset) for logging Transaction events */
   public static int LOG_LEVEL_TRANSACTION=2;
   /** Base level (offset) for logging Dialog events */
   public static int LOG_LEVEL_DIALOG=2;
   /** Base level (offset) for logging Call events */
   public static int LOG_LEVEL_CALL=1;
   /** Base level (offset) for logging UA events */
   public static int LOG_LEVEL_UA=0;

   /** Log level. Only logs with a level less or equal to this are written. */
   public static int debug_level=1;
   /** Path for the log folder where log files are written.
     * By default, it is used the "./log" folder.
     * Use ".", to store logs in the current root folder. */
   public static String log_path="log";
   /** The size limit of the log file [kB] */
   public static int max_logsize=2048; // 2MB
   /** The number of rotations of log files. Use '0' for NO rotation, '1' for rotating a single file */
   public static int log_rotations=0; // no rotation
   /** The rotation period, in MONTHs or DAYs or HOURs or MINUTEs
     * examples: log_rotation_time=3 MONTHS, log_rotations=90 DAYS 
     * Default value: log_rotation_time=2 MONTHS */
   private static String log_rotation_time=null;
   /** The rotation time scale */
   public static int rotation_scale=RotatingLog.MONTH;
   /** The rotation time value */
   public static int rotation_time=2;


   // ************************** costructor **************************


   /** Parses a single text line (read from the config file) */
   protected void parseLine(String line)
   {  String attribute;
      Parser par;
      int index=line.indexOf("=");
      if (index>0) {  attribute=line.substring(0,index).trim(); par=new Parser(line,index+1);  }
      else {  attribute=line; par=new Parser("");  }
      char[] delim={' ',','};

      // general configurations
      if (attribute.equals("default_port"))   { default_port=par.getInt(); return; }
      if (attribute.equals("default_transport_protocols")) { default_transport_protocols=par.getWordArray(delim); return; }
      if (attribute.equals("default_nmax_connections")) { default_nmax_connections=par.getInt(); return; }
      if (attribute.equals("use_rport")) { use_rport=(par.getString().toLowerCase().startsWith("y")); return; }
      if (attribute.equals("force_rport")) { force_rport=(par.getString().toLowerCase().startsWith("y")); return; }
      if (attribute.equals("max_forwards"))   { max_forwards=par.getInt(); return; }
      if (attribute.equals("retransmission_timeout")) { retransmission_timeout=par.getInt(); return; }
      if (attribute.equals("max_retransmission_timeout")) { max_retransmission_timeout=par.getInt(); return; }
      if (attribute.equals("transaction_timeout")) { transaction_timeout=par.getInt(); return; }
      if (attribute.equals("clearing_timeout"))    { clearing_timeout=par.getInt(); return; }
      if (attribute.equals("single_timer"))   { single_timer=(par.getString().toLowerCase().startsWith("y")); return; }
      if (attribute.equals("early_dialog"))   { early_dialog=(par.getString().toLowerCase().startsWith("y")); return; }
      if (attribute.equals("default_expires")){ default_expires=par.getInt(); return; }
      if (attribute.equals("ua_info"))        { ua_info=par.getRemainingString().trim(); return; }
      if (attribute.equals("server_info"))    { server_info=par.getRemainingString().trim(); return; }

      // debug and logs
      if (attribute.equals("debug_level"))    { debug_level=par.getInt(); return; }
      if (attribute.equals("log_path"))       { log_path=par.getString(); return; }
      if (attribute.equals("max_logsize"))    { max_logsize=par.getInt(); return; }
      if (attribute.equals("log_rotations"))  { log_rotations=par.getInt(); return; }
      if (attribute.equals("log_rotation_time"))   { log_rotation_time=par.getRemainingString(); return; }

      // old parameters
      if (attribute.equals("host_addr")) printLog("WARNING: parameter 'host_addr' is no more supported; use 'via_addr' instead.");
      if (attribute.equals("all_interfaces")) printLog("WARNING: parameter 'all_interfaces' is no more supported; use 'host_iaddr' for setting a specific interface or let it undefined.");
      if (attribute.equals("use_outbound")) printLog("WARNING: parameter 'use_outbound' is no more supported; use 'outbound_addr' for setting an outbound proxy or let it undefined.");
      if (attribute.equals("log_file")) printLog("WARNING: parameter 'log_file' is no more supported.");
   }  
      
   /** Converts the entire object into lines (to be saved into the config file) */
   protected String toLines()
   {  // currently not implemented..
      return "SipStack/"+release;
   }
 
   /** Costructs a non-static SipStack */
   private SipStack()
   {  
   }

   /** Inits SipStack */
   public static void init()
   {  init(null);
   }

   /** Inits SipStack from the specified <i>file</i> */
   public static void init(String file)
   {  
      (new SipStack()).loadFile(file);
            
      // user-agent info
      if (ua_info!=null && (ua_info.length()==0 || ua_info.equalsIgnoreCase(Configure.NONE) || ua_info.equalsIgnoreCase("NO-UA-INFO"))) ua_info=null;      

      // server info
      if (server_info!=null && (server_info.length()==0 || server_info.equalsIgnoreCase(Configure.NONE) || server_info.equalsIgnoreCase("NO-SERVER-INFO"))) server_info=null;      

      // timers
      Timer.SINGLE_THREAD=single_timer;

      // logs
      if (debug_level>0)
      {  if (log_rotation_time!=null)
         {  SipParser par=new SipParser(log_rotation_time);
            rotation_time=par.getInt();
            String scale=par.getString();
            if (scale==null) scale="null";
            if (scale.toUpperCase().startsWith("MONTH")) rotation_scale=RotatingLog.MONTH;
            else if (scale.toUpperCase().startsWith("DAY")) rotation_scale=RotatingLog.DAY;
            else if (scale.toUpperCase().startsWith("HOUR")) rotation_scale=RotatingLog.HOUR;
            else if (scale.toUpperCase().startsWith("MINUTE")) rotation_scale=RotatingLog.MINUTE;
            else
            {  rotation_time=7;
               rotation_scale=RotatingLog.DAY;
               printLog("Error with the log rotation time. Logs will rotate every week.");
            }
         }         
      }
      
      is_init=true;
      //if (file!=null) printLog("SipStack loaded",1);
   }

   /** Whether SipStack has been already initialized */
   public static boolean isInit()
   {  return is_init;
   }      


   // ************************ private methods ***********************
   
   /** Logs a string message. */
   private static void printLog(String str)
   {  System.out.println("SipStack: "+str);
   }
}
